package robocup.component.statistics;

import robocup.component.Synchro;
import robocup.component.ControllerNumbers.PLAY_MODE;
import robocup.component.actions.Action.TYPE;
import robocup.component.infotypes.InfoReceiver;
import robocup.component.infotypes.PlayModeInfo;
import robocup.component.infotypes.PlayerSayInfo;
import robocup.component.infotypes.PlayerTypesInfo;
import robocup.component.infotypes.RefereeInfo;
import robocup.component.infotypes.SenseBodyInfo;
import robocup.component.infotypes.VisualInfo;
import robocup.component.math.RCMath;

/**
 * Hole statistics.
 * 
 * statistic for hole measurement. used also for determing which of the sent
 * actions were considered by the SServer. A hole is defined as a sent action
 * that wasn't considered by the SoccerServer.
 * 
 * This statistics show the following:
 * 
 * main action holes main action holes (for cycles where the player has the
 * ball) turn neck action holes change view mode action holes cycles where no
 * action was sent Ratio of main actions calculated but not send (i.e. (turn
 * 0.0))
 * 
 */
public class HoleStatistic
    implements InfoReceiver {

  // hole in last cycle (main action)
  private boolean hole_main       = false;

  // hole in last cycle (turn neck action)
  private boolean hole_neck       = false;

  // hole in last cycle (change view mode action)
  private boolean hole_view       = false;

  // hole counter
  private int     holes_main      = 0;

  // hole neck
  private int     holes_neck      = 0;

  // holes view mode change
  private int     holes_view      = 0;

  // holes when with ball
  private int     holes_with_ball = 0;

  // cycles were no actions were sent
  private int     unsent          = 0;

  // main actions that were not sent because they wouldn't effect the
  // world
  private int     filteredMains   = 0;

  // action counter (main)
  private int     count_main      = 0;

  // action counter (neck)
  private int     count_neck      = 0;

  // action counter (view)
  private int     count_view      = 0;

  // action counter (main with ball)
  private int     count_with_ball = 0;

  // number of cycles
  private int     cycles          = 0;

  private Synchro synchro;

  /**
   * Constructor.
   * 
   */
  public HoleStatistic(
      final Synchro synchro) {

    this.synchro = synchro;
  }

  /**
   * This method has to be called each time a SB arrives.
   * 
   * @param sbInfo
   * @param synchro
   */
  public void update(final SenseBodyInfo sbInfo) {

    if (sbInfo.getCycle() <= 0) {
      return;
    }

    // reset
    this.hole_main = false;
    this.hole_neck = false;
    this.hole_view = false;

    this.cycles = sbInfo.getCycle();

    if (!synchro.wasSent()) {
      // nothing was sent
      this.unsent++;
      this.hole_main = true;
      this.hole_neck = true;
      this.hole_view = true;
    }
    else {

      if (this.synchro.getWorld().getPlayMode() == PLAY_MODE.PLAY_ON) {
        // main action was filtered
        if (synchro.getActions().getMain() != null
            && !synchro.getActions().getMain().isWorthSending()) {
          // world has not been updated yet
          if (synchro.getWorld().canKick()
              && synchro.getWorld().getPlayMode() == PLAY_MODE.PLAY_ON) {
            this.holes_with_ball++;
          }
          this.filteredMains++;
        }

        // main
        if (sbInfo.getMainActionsCountSum() == this.count_main
            && synchro.getActions().getMain() != null
            && synchro.getActions().getMain().isWorthSending()) {
          // System.out.println(cycles + "HOLE P:" +
          // synchro.parent.getNumber() + "-" + mainAction);
          this.hole_main = true;
          this.holes_main++;

          // world has not been updated yet
          if (synchro.getWorld().canKick()) {
            this.holes_with_ball++;
          }
        }

        // neck
        if (sbInfo.getCount(TYPE.TURN_NECK) == this.count_neck
            && synchro.getActions().getNeck() != null
            && synchro.getActions().getNeck().isWorthSending()) {
          this.hole_neck = true;
          this.holes_neck++;
        }
        // changeViewMode
        if (sbInfo.getCount(TYPE.CHANGE_VIEW_MODE) == this.count_view
            && synchro.getActions().getView() != null) {
          this.hole_view = true;
          this.holes_view++;
        }

        // world has not been updated yet
        if (synchro.getWorld().canKick()) {
          this.count_with_ball++;
        }
      }

      // update action counters
      this.count_main = sbInfo.getMainActionsCountSum();
      this.count_neck = sbInfo.getCount(TYPE.TURN_NECK);
      this.count_view = sbInfo.getCount(TYPE.CHANGE_VIEW_MODE);
    }
  }

  /**
   * prints the statistic.
   * 
   */
  public void show() {

    System.out.println("HOLE_STATS C"
        + this.cycles
        + " P:"
        + synchro.getWorld().getSelfRef().getNumber()
        + "\t MAIN:"
        + this.holes_main
        + " %:"
        + ((this.count_view + this.holes_view == 0) ? -1 : RCMath
            .round2((double) this.holes_main
                / (this.count_main + this.holes_main)
                * 100))
        + "\t WITH_BALL:"
        + this.holes_with_ball
        + " %:"
        + ((this.count_with_ball + this.holes_with_ball == 0) ? -1 : RCMath
            .round2((double) this.holes_with_ball
                / (this.count_with_ball + this.holes_with_ball)
                * 100))
        + "\t NECK:"
        + this.holes_neck
        + " %:"
        + ((this.count_view + this.holes_view == 0) ? -1 : RCMath
            .round2((double) this.holes_neck
                / (this.count_neck + this.holes_neck)
                * 100))
        + "\t VIEW:"
        + this.holes_view
        + " %:"
        + ((this.count_view + this.holes_view == 0) ? -1 : RCMath
            .round2((double) this.holes_view
                / (this.count_view + this.holes_view)
                * 100))
        + "\t UNSENT:"
        + this.unsent
        + " %:"
        + RCMath.round2((double) this.unsent / (this.cycles) * 100)
        + "\t FILTERED:"
        + this.filteredMains
        + " %:"
        + RCMath.round2((double) this.filteredMains / (this.cycles) * 100));
  }

  /**
   * The hole_main.
   * 
   * @return the hole_main
   */
  public boolean isHole_main() {

    return this.hole_main;
  }

  /**
   * The hole_neck.
   * 
   * @return the hole_neck
   */
  public boolean isHole_neck() {

    return this.hole_neck;
  }

  /**
   * The hole_view.
   * 
   * @return the hole_view
   */
  public boolean isHole_view() {

    return this.hole_view;
  }

  /**
   * The holes_main.
   * 
   * @return the holes_main
   */
  public int getHoles_main() {

    return this.holes_main;
  }

  /**
   * The holes_with_ball.
   * 
   * @return the holes_with_ball
   */
  public int getHoles_with_ball() {

    return this.holes_with_ball;
  }

  /**
   * The count_with_ball.
   * 
   * @return the count_with_ball
   */
  public int getCount_with_ball() {

    return this.count_with_ball;
  }

  /*
   * (non-Javadoc)
   * 
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.VisualInfo)
   */
  public void update(final VisualInfo info) {

    // TODO Auto-generated method stub

  }

  /*
   * (non-Javadoc)
   * 
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.RefereeInfo)
   */
  public void update(final RefereeInfo info) {

    // TODO Auto-generated method stub

  }

  /*
   * (non-Javadoc)
   * 
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.PlayModeInfo)
   */
  public void update(final PlayModeInfo info) {

    // TODO Auto-generated method stub

  }

  /*
   * (non-Javadoc)
   * 
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.PlayerSayInfo)
   */
  public void update(final PlayerSayInfo info) {

    // TODO Auto-generated method stub

  }

  /* (non-Javadoc)
   * @see robocup.component.infotypes.InfoReceiver#update(robocup.component.infotypes.PlayerTypesInfo)
   */
  public void update(final PlayerTypesInfo info) {

    // TODO Auto-generated method stub

  }
}
